package bit.client.model;

import org.jsoup.*;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.IOException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CourseGetter {
    private BitBasic basic;
    private URL functionUrl;
    private String viewstate;
    List<String> validyear;
    List<String> validsem;

    public static Course[][] getCoursebyWeek(int week, List<Course> courselist) {
        Course[][] rtval = new Course[7][14];
        for (Course course : courselist) {
            if (course.time != null && course.time.hasClass(week)) {
                List<Integer> courseNum;
                for (int i = 0; i < 7; i++) {
                    courseNum = course.time.timelist[i];
                    for (Integer j : courseNum) {
                        rtval[i][j] = course;
                    }
                }
            }
        }
        return rtval;
    }

    public static Course[] getCourseToday(int week, List<Course> courselist) {
        Calendar calendar = Calendar.getInstance();
        int weekday = calendar.get(Calendar.DAY_OF_WEEK);
        weekday = (weekday + 5) % 7;
        Course[] rtval = new Course[14];
        for (Course course : courselist) {
            if (course.time != null && course.time.hasClass(week)) {
                List<Integer> courseNum;
                courseNum = course.time.timelist[weekday];
                for (Integer i : courseNum) {
                    rtval[i] = course;
                }
            }
        }
        return rtval;
    }

    public List<Course> queryCoursesCurSem() throws IOException {
        List<Course> rtval = new ArrayList();
        Connection.Response response = basic.get(functionUrl);
        Document doc = response.parse();
        Elements tdlist = doc.select("#dgrdKb tbody").first().select("tr:not(.datagridhead)");
        for (Element td : tdlist) {
            Elements trlist = td.select("td");
            List<String> trString = trlist.eachText();
            Course course = new Course(trString.get(0), trString.get(1), trString.get(4), trString.get(6), trString.get(8), trString.get(7));
            rtval.add(course);
        }
        return rtval;
    }

    public List<Course> queryCoursesBySem(String year, String sem) throws IOException, OutOfValidYearOrSem {
        year = year.trim();
        sem = sem.trim();
        if (!validyear.contains(year) || !validsem.contains(sem)) throw new OutOfValidYearOrSem();
        Map<String, String> param = new HashMap();
        param.put("__EVENTARGUMENT", "");
        param.put("__EVENTTARGET", "xnd");
        param.put("__VIEWSTATE", viewstate);
        param.put("xnd", year);
        param.put("xqd", sem);
        Connection.Response response = basic.post(functionUrl, param);
        Document doc = response.parse();
        Elements tdlist = doc.select("#dgrdKb tbody").first().select("tr:not(.datagridhead)");
        List<Course> rtval = new ArrayList();
        for (Element td : tdlist) {
            Elements trlist = td.select("td");
            List<String> trString = trlist.eachText();
            Course course = new Course(trString.get(0), trString.get(1), trString.get(4), trString.get(6), trString.get(8), trString.get(7));
            rtval.add(course);
        }
        return rtval;
    }

    public static int getCurrentWeek() throws IOException {
        String url = "http://10.0.6.51/";
        Document doc = Jsoup.connect(url).get();
        Element element = doc.select(".black font b").first();
        return Integer.parseInt(element.text());
    }

    private void getValidYear(Document doc) {
        Elements optList = doc.select("#xnd option");
        List<String> rtval = new ArrayList();
        for (Element opt : optList) {
            if (opt.text().isEmpty()) continue;
            rtval.add(opt.text());
        }
        validyear = rtval;
    }

    private void getValidSem(Document doc) {
        Elements optlist = doc.select("#xqd option");
        List<String> rtval = new ArrayList();
        for (Element opt : optlist) {
            rtval.add(opt.text());
        }
        validsem = rtval;
    }

    CourseGetter(BitBasic basic) throws IOException {
        this.basic = basic;
        functionUrl = basic.tableURL;
        Connection.Response response = basic.get(functionUrl.toString());
        Document doc = response.parse();
        viewstate = doc.select("input[name=__VIEWSTATE]").first().attr("value");
        getValidSem(doc);
        getValidYear(doc);

    }

    public static class Course {
        String name;
        float credit;
        String school;
        String teacher;
        String place;
        CourseTime time;

        Course(String _name, String _credit, String _school, String _teacher, String _place, String _time) {
            name = _name;
            credit = Float.parseFloat(_credit);
            school = _school;
            teacher = _teacher;
            place = _place;
            try {
                time = new CourseTime(_time);
            } catch (Exception e) {
                time = null;
            }
        }

        public static class CourseTime {
            int startWeek;
            int endWeek;

            boolean hasClass(int week) {
                if (week > startWeek && week < endWeek) return true;
                else return false;
            }

            @SuppressWarnings("unchecked")
            private ArrayList<Integer>[] timelist = (ArrayList<Integer>[]) new ArrayList[7];

            CourseTime(String rawTime) throws Exception {
                for (int i = 0; i < 7; i++) {
                    timelist[i] = new ArrayList<>();
                }
                rawTime = rawTime.trim();
                String[] timeList = rawTime.split(";");
                Pattern pattern = Pattern.compile("周(.)第([0-9,]+)小?节 ?\\{第(\\d+)-(\\d+)周\\}");
                for (String eachTime : timeList) {
                    Matcher result = pattern.matcher(eachTime);
                    if (!result.find() || result.groupCount() != 4)
                        throw new Exception();
                    else {
                        startWeek = Integer.parseInt(result.group(3));
                        endWeek = Integer.parseInt(result.group(4));
                        String[] classes = result.group(2).split(",");
                        switch (result.group(1)) {
                            case "一":
                                for (String i : classes) {
                                    timelist[0].add(new Integer(i));
                                }
                                break;
                            case "二":
                                for (String i : classes) {
                                    timelist[1].add(new Integer(i));
                                }
                                break;
                            case "三":
                                for (String i : classes) {
                                    timelist[2].add(new Integer(i));
                                }
                                break;
                            case "四":
                                for (String i : classes) {
                                    timelist[3].add(new Integer(i));
                                }
                                break;
                            case "五":
                                for (String i : classes) {
                                    timelist[4].add(new Integer(i));
                                }
                                break;
                            case "六":
                                for (String i : classes) {
                                    timelist[5].add(new Integer(i));
                                }
                                break;
                            case "日":
                                for (String i : classes) {
                                    timelist[6].add(new Integer(i));
                                }
                                break;
                        }
                    }
                }
            }
        }

    }
}
